package cn.rslee.scala.demos

object FuncApp extends App {
  
  // 单行函数
  def add( x :Int) : Int = x+1
  
  // 匿名函数
  def adder = (x : Int) => x
  
  // 类方法
  class Id{
    def apply(x : Int) = x
  }
  
  // apply是特殊方法，你执行new命令的时候就执行了
  val myId = new Id()
  
  object IDS{
    def apply(x : Int) = x+1
  }
  
  // 匿名内部类
  val inner = new {
    def apply(x : Int) = x
  }
  
  //case 块冒充function
  val myCase : Int => Int = {
    case x => x
  }
  
  //输出
  println(add(3))
  println(adder(3))
  println(myId.apply(3))
  println(IDS.apply(3))
  println(inner.apply(3))
  println(myCase(3))
  
  // 多参数函数定义
  def h(x : Int, y : Int) : Int = x +y
  
  // 库里化(柯里化)curried
  def hc(x:Int)(y:Int) : Int = x+y
  
  println(hc(3)(4))
  
  //也可以先调用后面的参数再调用前面的
  val plus3 = hc(_:Int) (3)
  val plus_3 = hc(3) _
  
  println(plus3(10))
  println(plus_3(10))
  
  //如果没有返回值或者返回值是Unit,我们可以不指定返回类型
  
  def proc(a : Int){
    println("I'm "+a)
  }
  
  //当然你也可以显式指定
  def proc2(a : Int):Unit = {
		  println("I'm "+a)
  }
  
  proc(10)
  proc2(10)
  
  //无参的函数调用可以省略括号
  
  def argless : Unit = println("argless got called!")
  
  argless
  
  //惰性变量 (lazy fields)。简单来说调用过一次以后，我就可以缓存调用的结果了，类似java里面的单例模式的实现。
  //区别在于，Java里面这里的变量通常绑定到class对象里面（static）,无法在函数里面单独实现(函数作用域有限)，但是
  //scala是一门面向函数式编程的语言，函数还是经常会传来传去的，所有就弄了个lazy关键字实现
  
  /**
   * val field:String = null
   * def getField():String = {
   * 		if(field == null){
   * 			field = "hehe"
   * 		}
   *   field
   * }
   * 
   * 
   * */
  
  class LazyClass{
    
    lazy val x = {println("这里是计算x值的过程");3} //多行代码在一行写的时候要加分号(;)
    
  }
  val lc = new LazyClass
  println(lc.x)
  println(lc.x)
  println(lc.x)
  
  // 基于传入函数的惰性参数实现
  /**
   * 解析一下：
   * x : => Int 这句话指的是lazyId函数接受的参数是一个函数,函数不带参数，这个函数返回的是Int类型的数字
   * 三次x指的是调用三次传入的函数(不带参数)
   * 这里使用了return关键字，指明我们返回的指就是调用函数后的值，类似于java里面的代理模式
   * */
  def lazyId(x : => Int) : Int = {
    x
    x
    x
    return x ;
  }
  
  println(lazyId{println("used");3})
  
  //scala实现代理模式
  def proxy(name:String,func : String=>Unit) = {
    func(name)
  }
  
  val p = (x:String) => println("你好，"+x)
  proxy("rslee",p)
  
  //多参数
  def proxy2(name:String,func : (String,Int)=>Unit) = {
    func(name,182)
  }
  
  val p2 = (x:String,y:Int) => println("name:"+x+",age:"+y)
  
  proxy2("dd",p2)
  
}